package cn.nfwx.tv.widget.ijkplayer;

import android.content.Context;
import android.media.MediaPlayer;
import android.os.Build;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.FrameLayout;

import com.hdl.m3u8.M3U8InfoManger;
import com.hdl.m3u8.bean.M3U8;
import com.hdl.m3u8.bean.OnM3U8InfoListener;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;

import cn.nfwx.tv.helper.ActivityHelper;
import cn.nfwx.tv.okhttp.UrlHelper;
import cn.nfwx.tv.util.LogUtil;
import tv.danmaku.ijk.media.player.IMediaPlayer;
import tv.danmaku.ijk.media.player.IjkMediaPlayer;

/**
 * Created by dell on 2018/3/22.
 */

public class IjkVideoView extends FrameLayout implements OnM3U8InfoListener {

    private static final String TAG = IjkVideoView.class.getSimpleName();

    /**
     * 由ijkplayer提供，用于播放视频，需要给他传入一个surfaceView
     */
    private IMediaPlayer mMediaPlayer = null;

    private boolean _isPlaying;
    private boolean _isPausing;
    private boolean _isHandPausing;
    private boolean _isStop;
    private boolean _isLive;

    private boolean _needSeekToOldPos = false;
    /**
     * 视频文件地址
     */
    private String mPath = "";
    private String gid;

    private SurfaceView surfaceView;
    private SurfaceHolder SurfaceHolder;

    private IjkVideoListener listener;
    private Context mContext;
    private LmnSurfaceCallback surfaceViewCallback;

    private boolean _isEnd;
    private boolean _isLoad = true;

    private long currentPosition = 0;
    private long timeCode = 0;
    private View _loadingView;

    private boolean _liveSeek;

    public IjkVideoView(@NonNull Context context) {
        super(context);
        initVideoView(context);
    }

    public IjkVideoView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initVideoView(context);
    }

    public IjkVideoView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initVideoView(context);
    }

    private void initVideoView(Context context) {
        mContext = context;

        //获取焦点，不知道有没有必要~。~
        setFocusable(true);
    }

    /**
     * 设置视频地址。
     * 根据是否第一次播放视频，做不同的操作。
     *
     * @param path the path of the video.
     */
    public void setVideoPath(String path) {
        if (_isLive) {
            path = UrlHelper.getIjkLivePath(path);
            M3U8InfoManger.getInstance().getM3U8Info(path, IjkVideoView.this);
        }
        //HttpProxyCacheServer proxy = NFWXApplication.getInstance().getProxy(mContext);
        //path = proxy.getProxyUrl(path);
        _isEnd = false;
        _isLoad = true;
        currentPosition = 0;
        _isHandPausing = false;
        _isPlaying = true;
        _isStop = false;
        _isPausing = false;
        if (TextUtils.isEmpty(mPath)) {
            //如果是第一次播放视频，那就创建一个新的surfaceView
            LogUtil.e(TAG, "createSurfaceView");
            mPath = path;
            createSurfaceView();
        } else {
            //否则就直接load
            LogUtil.e(TAG, "load");
            mPath = path;
            load();
        }
        showLoading();
    }

    /**
     * 新建一个surfaceview
     */
    private void createSurfaceView() {
        //生成一个新的surface view
        surfaceView = new SurfaceView(mContext);
        surfaceViewCallback = new LmnSurfaceCallback();
        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT
                , LayoutParams.MATCH_PARENT, Gravity.CENTER);
        surfaceView.setLayoutParams(layoutParams);
        SurfaceHolder = surfaceView.getHolder();
        SurfaceHolder.addCallback(surfaceViewCallback);
        this.addView(surfaceView, 0);
    }

    public boolean isPlaying() {
        return _isPlaying;
    }

    public void isEnd(boolean b) {
        _isEnd = b;
    }

    public void setLive(boolean live) {
        _isLive = live;
    }

    /**
     * 解析m3u8信息流
     *
     * @param m3U8
     */
    @Override
    public void onSuccess(M3U8 m3U8) {
        try {
            if (!m3U8.getTsList().isEmpty()) {
                String fileName;
                if (m3U8.getTsList().size() > 3) {
                    fileName = m3U8.getTsList().get(m3U8.getTsList().size() - 3).getFileName();
                } else {
                    fileName = m3U8.getTsList().get(0).getFileName();
                }
                if (!TextUtils.isEmpty(fileName) && fileName.startsWith("live-") && fileName.endsWith(".ts")) {
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
                    String timeStr = fileName.substring("live-".length(), fileName.lastIndexOf(".ts"));
                    Log.v(TAG, "获取成功了" + timeStr);
                    try {
                        Date date = dateFormat.parse(timeStr);
                        timeCode = date.getTime();
                    } catch (Exception e) {
                        timeCode = System.currentTimeMillis();
                    }
                }
            }
        } catch (Exception e) {
            timeCode = System.currentTimeMillis();
        }
    }

    @Override
    public void onStart() {
        Log.v(TAG, "开始获取信息");
    }

    @Override
    public void onError(Throwable errorMsg) {
        Log.v(TAG, "出错了" + errorMsg.getMessage());
    }

    public boolean isLoad() {
        return _isLoad;
    }

    public void isLoad(boolean _isLoad) {
        this._isLoad = _isLoad;
    }

    public void setGid(String gid) {
        this.gid = gid;
    }

    public void seekByTimeCode(long byTimeCode) {
        String timeUrl = UrlHelper.getTimesShiftUrl(gid, byTimeCode);
        _liveSeek = true;
        setVideoPath(timeUrl);
    }

    public String getPath() {
        return mPath;
    }

    /**
     * surfaceView的监听器
     */
    private class LmnSurfaceCallback implements SurfaceHolder.Callback {
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            Log.v(TAG, "IjkVideoView surfaceCreated");
            if (_isEnd || !_isLoad) {
                _isEnd = false;
                _isLoad = true;
                return;
            }
            load();
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            Log.v(TAG, "IjkVideoView surfaceChanged");
            //surfaceview创建成功后，加载视频

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            Log.v(TAG, "IjkVideoView surfaceDestroyed");
            if (_isPausing || _isHandPausing) {
                _needSeekToOldPos = true;
            }
            //closePlayer();
        }
    }


    /**
     * 加载视频
     */
    private void load() {
        //每次都要重新创建IMediaPlayer
        createPlayer();
        //给mediaPlayer设置视图
        try {
            mMediaPlayer.setDataSource(mPath);
        } catch (IOException e) {
            e.printStackTrace();
        }
        mMediaPlayer.setDisplay(SurfaceHolder);
        mMediaPlayer.prepareAsync();
    }

    private void closePlayer() {
        if (mMediaPlayer != null) {
            mMediaPlayer.stop();
            mMediaPlayer.setDisplay(null);
            mMediaPlayer = null;
        }
    }

    /**
     * 创建一个新的player
     */
    private void createPlayer() {
        if (mMediaPlayer != null) {
            mMediaPlayer.stop();
            mMediaPlayer.setDisplay(null);
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
        final IjkMediaPlayer ijkMediaPlayer = new IjkMediaPlayer();
//        //开启硬解码
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            if (isMediaCodecList()) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1L);
                }
            }
        }
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "probesize", 1024L);
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "flush_packets", 1L);
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 1L);
        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1L);
        mMediaPlayer = ijkMediaPlayer;

        if (listener != null) {
            mMediaPlayer.setOnPreparedListener(new IMediaPlayer.OnPreparedListener() {
                @Override
                public void onPrepared(IMediaPlayer iMediaPlayer) {
                    listener.onPrepared(iMediaPlayer);
                    if (ActivityHelper.getInstance().isBackground()) {
                        return;
                    }
                    if (!_needSeekToOldPos) {
                        Log.v(TAG, "onPrepared to start");
                        _isPlaying = true;
                        _isPausing = false;
                        _isStop = false;
                        _needSeekToOldPos = false;
                        mMediaPlayer.start();
                        hideLoading();
                    } else {
                        Log.v(TAG, "onPrepared seed to position : " + currentPosition + " & _isHandPausing :" + _isHandPausing);
                        if (_isLive) {
                            _isPlaying = true;
                            _isPausing = false;
                            _isStop = false;
                            _needSeekToOldPos = false;
                            mMediaPlayer.start();
                            hideLoading();
                            if (_isHandPausing) {
                                postDelayed(new Runnable() {
                                    @Override
                                    public void run() {
                                        _isPlaying = false;
                                        _isPausing = true;
                                        _isHandPausing = true;
                                        _needSeekToOldPos = false;
                                        _isStop = false;
                                        mMediaPlayer.pause();
                                    }
                                }, 200);
                            }
                        } else {
                            hideLoading();
                            _isPlaying = true;
                            _isPausing = false;
                            _needSeekToOldPos = false;
                            _isStop = false;
                            iMediaPlayer.seekTo(currentPosition);
                            iMediaPlayer.start();
                            if (_isHandPausing) {
                                postDelayed(new Runnable() {
                                    @Override
                                    public void run() {
                                        _isPlaying = false;
                                        _isPausing = true;
                                        _needSeekToOldPos = false;
                                        _isStop = false;
                                        mMediaPlayer.pause();
                                    }

                                }, 500);
                            }
                        }
                    }
                    LogUtil.v(TAG, "setOnPreparedListener---_liveSeek" + _liveSeek);
                    if (_liveSeek) {
                        _liveSeek = false;
                        postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                listener.onSeekComplete(mMediaPlayer);
                            }
                        }, 200);
                    }
                }
            });
            mMediaPlayer.setOnInfoListener(new IMediaPlayer.OnInfoListener() {
                @Override
                public boolean onInfo(IMediaPlayer iMediaPlayer, int what, int extra) {
                    listener.onInfo(iMediaPlayer, what, extra);
                    if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START) {
                        LogUtil.e(TAG, "MEDIA_INFO_BUFFERING_START");
                        showLoading();
                    } else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END) {
                        LogUtil.e(TAG, "MEDIA_INFO_BUFFERING_END");
                        hideLoading();
                    } else if (what == IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED) {
                        LogUtil.e(TAG, "MEDIA_INFO_VIDEO_ROTATION_CHANGED");
                    }
                    return false;
                }
            });
            mMediaPlayer.setOnSeekCompleteListener(listener);
            mMediaPlayer.setOnBufferingUpdateListener(listener);
            mMediaPlayer.setOnErrorListener(new IMediaPlayer.OnErrorListener() {
                @Override
                public boolean onError(IMediaPlayer iMediaPlayer, int i, int i1) {
                    return false;
                }
            });
        }
    }

    public void setListener(final IjkVideoListener listener) {
        this.listener = listener;
        if (mMediaPlayer != null) {
            mMediaPlayer.setOnPreparedListener(listener);
            mMediaPlayer.setOnInfoListener(listener);
            mMediaPlayer.setOnSeekCompleteListener(listener);
            mMediaPlayer.setOnBufferingUpdateListener(listener);
            mMediaPlayer.setOnErrorListener(listener);
        }
    }

    /**
     * @param lastPath
     */
    public void restart(String lastPath) {
        setVideoPath(lastPath);
    }

    /**
     * -------======--------- 下面封装了一下控制视频的方法
     */
    public void start() {
        LogUtil.v(TAG, "start");
        if (mMediaPlayer != null) {
            _isPlaying = true;
            _isPausing = false;
            _isStop = false;
            _isHandPausing = false;
            mMediaPlayer.setDisplay(SurfaceHolder);
            mMediaPlayer.start();
        } else {
            if (!TextUtils.isEmpty(mPath)) {
                load();
            }
        }
    }

    public void release() {
        LogUtil.v(TAG, "release");
        mPath = null;
        if (SurfaceHolder != null) {
            SurfaceHolder.removeCallback(surfaceViewCallback);
            SurfaceHolder = null;
        }
        if (mMediaPlayer != null) {
            mMediaPlayer.reset();
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
        if (surfaceView != null) {

        }
    }

    public void pause() {
        LogUtil.v(TAG, "pause");
        if (_isPausing) {
            return;
        }
        if (mMediaPlayer != null) {
            _isPlaying = false;
            _isStop = false;
            _isPausing = true;
            _isHandPausing = false;
            mMediaPlayer.pause();
            if (!_isLive) {
                currentPosition = mMediaPlayer.getCurrentPosition();
            }
        }
    }

    public void handpause() {
        LogUtil.v(TAG, "handpause");
        if (_isHandPausing) {
            return;
        }
        if (mMediaPlayer != null) {
            _isPlaying = false;
            _isStop = false;
            _isPausing = true;
            _isHandPausing = true;
            mMediaPlayer.pause();
            if (!_isLive) {
                currentPosition = mMediaPlayer.getCurrentPosition();
            }
        }
    }

    public void stop() {
        LogUtil.v(TAG, "stop");
        if (_isStop) {
            return;
        }
        if (mMediaPlayer != null) {
            _isPlaying = false;
            _isPausing = false;
            _isStop = true;
            _isHandPausing = false;
            timeCode = 0;
            mMediaPlayer.stop();
        }
    }


    public void reset() {
        if (mMediaPlayer != null) {
            _isPlaying = false;
            mMediaPlayer.reset();
            timeCode = 0;
        }
    }


    public long getDuration() {
        if (mMediaPlayer != null) {
            return mMediaPlayer.getDuration();
        } else {
            return 0;
        }
    }

    public long getTimeCode() {
        if (mMediaPlayer != null) {
            if (timeCode == 0) {
                return getCurrentPosition();
            } else {
                return (timeCode + getCurrentPosition()) / 1000L;
            }
        } else {
            return 0;
        }
    }


    public long getCurrentPosition() {
        if (mMediaPlayer != null) {
            return mMediaPlayer.getCurrentPosition();
        } else {
            return 0;
        }
    }


    public void seekTo(long l) {
        if (mMediaPlayer != null) {
            mMediaPlayer.seekTo(l);
        }
    }

    public void clearScreen() {
        if (surfaceView != null) {
            _isLoad = false;
            LayoutParams l1 = (LayoutParams) surfaceView.getLayoutParams();
            this.removeView(surfaceView);
            this.addView(surfaceView, 0);
            surfaceView.setLayoutParams(l1);
            SurfaceHolder = surfaceView.getHolder();
            gid = "";
        }
    }

    public void removeSurfaceView() {
        if (surfaceView != null) {
            this.removeView(surfaceView);
            gid = "";
        }
    }

    public void setLoadingView(View v, int width, int height) {
        if (v == _loadingView) return;
        if (_loadingView != null) this.removeView(_loadingView);
        _loadingView = v;
        if (v == null) return;
        if (width == 0) width = LayoutParams.WRAP_CONTENT;
        if (height == 0) height = LayoutParams.WRAP_CONTENT;
        LayoutParams l = new LayoutParams(width, height);
        l.gravity = Gravity.CENTER;
        this.addView(v);
        v.setLayoutParams(l);
        v.requestLayout();
    }

    public void showLoading() {
        if (_loadingView != null) {
            _loadingView.setVisibility(VISIBLE);
        }
    }

    public void hideLoading() {
        if (_loadingView != null) {
            _loadingView.setVisibility(GONE);
        }
    }

    public boolean isMediaCodecList() {
        boolean _hasHardAVC = false;
        try {
            //_hasHardAVC = P2PSMediaPlayer.hasHardwareCodecForType("video/avc");
//            if (_hasHardAVC) {
//                _hasHardAVC = isSupportMediaCodecHardDecoder();
//            }
        } catch (Throwable e) {
            _hasHardAVC = false;
        }
        return _hasHardAVC;
    }

    public boolean isSupportMediaCodecHardDecoder() {
        boolean isHardcode = false;
        //读取系统配置文件/system/etc/media_codecc.xml
        File file = new File("/system/etc/media_codecs.xml");
        InputStream inFile = null;
        try {
            inFile = new FileInputStream(file);
        } catch (Exception e) {
            // TODO: handle exception
        }

        if (inFile != null) {
            XmlPullParserFactory pullFactory;
            try {
                pullFactory = XmlPullParserFactory.newInstance();
                XmlPullParser xmlPullParser = pullFactory.newPullParser();
                xmlPullParser.setInput(inFile, "UTF-8");
                int eventType = xmlPullParser.getEventType();
                while (eventType != XmlPullParser.END_DOCUMENT) {
                    String tagName = xmlPullParser.getName();
                    switch (eventType) {
                        case XmlPullParser.START_TAG:
                            if ("MediaCodec".equals(tagName)) {
                                String componentName = xmlPullParser.getAttributeValue(0);

                                if (componentName.startsWith("OMX.")) {
                                    if (!componentName.startsWith("OMX.google.")) {
                                        isHardcode = true;
                                    }
                                }
                            }
                    }
                    eventType = xmlPullParser.next();
                }
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
        return isHardcode;
    }
}
